package isssr.bean.boundary;

import isssr.bean.entity.Role;
import isssr.bean.entity.User;
import isssr.bean.utility.StorageUtility;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Comparator;

import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortOrder;

public class LazyEnactorDataModel extends LazyDataModel<User> {

	private class LazyUserComparator implements Comparator
	{
		private SortOrder order;
		private String field;

		protected LazyUserComparator(String field, SortOrder order)
		{
			this.field=field;
			this.order=order;
		}
		
		@Override
		public int compare(Object arg0, Object arg1) {
			
			User user0 = (User) arg0;
			User user1 = (User) arg1;
			
			System.out.println("ordertype " + (this.order == SortOrder.ASCENDING ? "ascen" : (this.order == SortOrder.DESCENDING ? "descen" : "unord")) );
			System.out.println("orderfield " + this.field);
			if(this.order == SortOrder.UNSORTED)
				return 0;
			
			if(this.field.equals("username"))
			{
				return compareString(user0.getUsername(), user1.getUsername());
			}
			else if(this.field.equals("firstname"))
			{
				return compareString(user0.getFirstName(), user1.getFirstName());
			}
			else if(this.field.equals("lastname"))
			{
				return compareString(user0.getLastName(), user1.getLastName());
			}
			else if(this.field.equals("email"))
			{
				return compareString(user0.getEmail(), user1.getEmail());
			}
			else if(this.field.equals("role.title"))
			{
				return compareString(user0.getRole().getTitle(), user1.getRole().getTitle());
			}
			
			return 0;
		}

		private int compareString(String arg0, String arg1) {
			
			int lexicographicalOrder = arg0.compareTo(arg1);
			int normalizedOrder;
			
			if(lexicographicalOrder > 0)
				normalizedOrder = 1;
			else if(lexicographicalOrder < 0)
				normalizedOrder = -1;
			else
				normalizedOrder = 0;
			
			return correctOrdering(normalizedOrder);
			
		}

		private int correctOrdering(int order) {
			
			int finalOrder;
			
			switch(this.order)
			{
			case ASCENDING:
				finalOrder = order;
				break;
			case DESCENDING:
				finalOrder = (order * -1);
				break;
			default:
				finalOrder = 0;
				break;
			}
			
			System.out.println("ordered: " + finalOrder);
			
			return finalOrder;
		}
		
	}
	
	private ArrayList<User> fetchedUser;
	
	private HashMap<String, String> labelConversion;

	private User currentUser;
	
	public LazyEnactorDataModel(User currentUser)
	{
		this.currentUser = currentUser;
		this.fetchedUser = new ArrayList<User>();
	}
	
	@Override
	public void setRowIndex(int rowIndex) {
	    /*
	     * The following is in ancestor (LazyDataModel):
	     * this.rowIndex = rowIndex == -1 ? rowIndex : (rowIndex % pageSize);
	     */
	    if (rowIndex == -1 || getPageSize() == 0) {
	        super.setRowIndex(-1);
	    }
	    else
	        super.setRowIndex(rowIndex % getPageSize());
	}
	
	@Override  
    public Object getRowKey(User user) {  
        return user.getId();  
    }
	
	@Override  
    public User getRowData(String rowKey) {  
		
		Integer userID;
		
		for(User user : this.fetchedUser) {  
            
			userID = Integer.parseInt(rowKey);
			
			if(user.getId().equals(userID))  
			{
				return user;  
                
			}  
		}
        return null;  
    }  
	
	private Role loadRole(String title)
	{
		Role prototypeRole = new Role(), resultRole = null;
		if(title != null)
		{
			prototypeRole.setTitle(title);
			
			try
			{
				Iterator<Role> role_it = (Iterator<Role>) prototypeRole.loadSiblings();
				if(role_it.hasNext())
				{
					resultRole = role_it.next();
				}
			}
			catch(Exception ex)
			{
				ex.printStackTrace();
			}
			
		}
		
		return resultRole;
	}
	
	
	@Override
	public List<User> load(int firstRecord, int pageSize, String sortField, SortOrder sortOrder,
			Map<String, String> filters) {
		
		ArrayList<User> enactorList = StorageUtility.getEligibleEnactors(this.currentUser, firstRecord, pageSize);
		System.out.println("record number: " + enactorList.size());
		ArrayList<User> tempList;
		this.fetchedUser = enactorList;
		
		tempList = filterList(enactorList, filters);
		
		setRowCount(tempList.size());
		
		if(sortField != null) {  
			LazyUserComparator comparator = new LazyUserComparator(sortField, sortOrder); 
            Collections.sort(tempList, comparator);  
        }  
		
		return tempList;
		
	}
	
	private ArrayList<User> filterList(ArrayList<User> enactorList,
			Map<String, String> filters) {
		ArrayList<User> filteredList = (ArrayList<User>) enactorList.clone();
		
		for(Entry<String, String> e : filters.entrySet())
		{
			if(e.getKey().equals("username"))
			{
				for(User user : enactorList)
				{
					if(!user.getUsername().equals((String)e.getValue()))
					{
						filteredList.remove(user);
					}
				}
			}
			else if(e.getKey().equals("firstName"))
			{
				for(User user : enactorList)
				{
					if(!user.getFirstName().equals((String)e.getValue()))
					{
						filteredList.remove(user);
					}
				}
			}
			else if(e.getKey().equals("lastName"))
			{
				for(User user : enactorList)
				{
					if(!user.getLastName().equals((String)e.getValue()))
					{
						filteredList.remove(user);
					}
				}
			}
			else if(e.getKey().equals("email"))
			{
				for(User user : enactorList)
				{
					if(!user.getEmail().equals((String)e.getValue()))
					{
						filteredList.remove(user);
					}
				}
			}
			else if(e.getKey().equals("role.title"))
			{
				filterListByRole(filteredList, (String) e.getValue());
			}
		}
		return filteredList;
	}

	private void filterListByRole(ArrayList<User> filteredList, String value) {
		
		Role prototypeRole = new Role();
		prototypeRole.setTitle(value);
		
		ArrayList<User> userToRemove = new ArrayList<User>();
		ArrayList<Role> roles = new ArrayList<Role>();
		
		try
		{
			Iterator<Role> iterator = (Iterator<Role>)prototypeRole.loadSiblings();

			if(iterator==null) 
			{
				filteredList.clear();
				return;
			}
			
			while(iterator.hasNext())
			{
				roles.add(iterator.next());
			}
			
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}
		
		if(roles==null) return;
		
		for(User user : filteredList)
		{
			if(!roles.contains(user.getRole()))
			{
				userToRemove.add(user);
			}
		}
		
		filteredList.removeAll(userToRemove);
		
		return;
	}

	/*
	@Override
	public List<User> load(int firstRecord, int pageSize, String sortField, SortOrder sortOrder,
			Map<String, String> filters) {
		
		System.out.println("initial value: " + firstRecord + " pageSize: " + pageSize);
		Role userRole = null;
		String prototypeRoleTitle = null;
		User prototypeUser = new User();
		
		System.out.println("filterSize: " + filters.size());
		
		for(Entry<String, String> e : filters.entrySet())
		{
			
			if(e.getKey().equals("username"))
			{
				prototypeUser.setUsername(e.getValue());
			}
			else if(e.getKey().equals("firstName"))
			{
				prototypeUser.setFirstName(e.getValue());
			}
			else if(e.getKey().equals("lastName"))
			{
				prototypeUser.setLastName(e.getValue());
			}
			else if(e.getKey().equals("email"))
			{
				prototypeUser.setEmail(e.getValue());
			}
			else if(e.getKey().equals("role.title"))
			{
				prototypeRoleTitle = (String ) e.getValue();
			}
			
		}
		
		prototypeUser.setRole(userRole);
		ArrayList<User> result = new ArrayList<User>();
		ArrayList<String> roleTitles = findRoleTitles(prototypeRoleTitle);
		
		try
		{
			
			if(prototypeRoleTitle != null)
			{
				//int pageNumber = ( firstRecord / pageSize )  + 1;
				Iterator<User> users = (Iterator<User>) prototypeUser.loadSiblings(0, 0);
				
				int userCounter = 0;
				
				User user;
				while(users.hasNext() && result.size() < pageSize)
				{
					user = users.next();
					if(roleTitles.contains(user.getRole().getTitle()))
					{
						if(userCounter<firstRecord)
							userCounter++;
						else
							result.add(user);
					}
				}
			}
			else
			{

				int pageNumber = ( firstRecord / pageSize )  + 1;
				Iterator<User> users = (Iterator<User>) prototypeUser.loadSiblings(pageNumber, pageSize);
				
				User user;
				while(users.hasNext())
				{
					user = users.next();
					result.add(user);
				}
			}
			
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}

		if(sortField != null) {  
			LazyUserComparator comparator = new LazyUserComparator(sortField, sortOrder); 
            Collections.sort(result, comparator);  
        }  
		
		int dataSize = result.size();
		this.setRowCount(dataSize);
		
		this.fetchedUser = result;
		
		return result;
		
	}
*/
	private ArrayList<String> findRoleTitles(String prototypeRoleTitle) {
		
		Role prototypeRole = new Role();
		prototypeRole.setTitle(prototypeRoleTitle);
		ArrayList<String> matchingTitles =  new ArrayList<String>();
		
		try
		{
			Iterator<Role> roles = (Iterator<Role>) prototypeRole.loadSiblings();
		
			while(roles.hasNext());
			{
				matchingTitles.add(roles.next().getTitle());
			}
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}
		
		
		return matchingTitles;
	}

}
